package model

import (
	"reflect"
	"regexp"
	"time"
)

type Prj_Regexp_Interface interface {
	Validate(string) bool
}

type PARA_TYPE_PRJ int
type PARA_TYPE_UUID string

const (
	PRJ_PATTERN      = `^[a-zA-Z0-9]{3,30}$`
	PRJ_UUID_PATTERN = `^[a-fA-F0-9]{8}-([a-fA-F0-9]{4}-){3}[a-fA-F0-9]{12}$`
)

func (prj *PARA_TYPE_PRJ) Validate(inStr string) bool {
	re := regexp.MustCompile(PRJ_PATTERN)
	return re.MatchString(inStr)
}

func (prj *PARA_TYPE_UUID) Validate(inStr string) bool {
	re := regexp.MustCompile(PRJ_UUID_PATTERN)
	return re.MatchString(inStr)
}

type PrjModel struct {
	Name      string     `json:"name,string"`
	Path      string     `json:"path,string"`
	Owner     string     `json:"owner,string"`
	Duration  int64      `json:"duration,string"`
	UniCode   string     `json:"unicode,omitempty"`
	Status    PRJ_STATUS `json:"status,omitempty"`
	BuildTime time.Time  `json:"build_time,omitempty"`
}

type PrjModelFunc func(*PrjModel)

func WithPrjModelName(name string) PrjModelFunc {
	return func(p *PrjModel) {
		p.Name = name
	}
}

func WithPrjModelPath(_path string) PrjModelFunc {
	return func(p *PrjModel) {
		p.Path = _path
	}
}

func WithPrjModelOwner(own string) PrjModelFunc {
	return func(p *PrjModel) {
		p.Owner = own
	}
}

func WithPrjModelDuration(dur int64) PrjModelFunc {
	return func(p *PrjModel) {
		p.Duration = dur
	}
}

func WithPrjModelUniCode(uni string) PrjModelFunc {
	return func(p *PrjModel) {
		p.UniCode = uni
	}
}

func NewPrjModelByOpt(opts ...PrjModelFunc) *PrjModel {
	pm := &PrjModel{}
	for _, opt := range opts {
		opt(pm)
	}
	return pm
}

func (p *PrjModel) UpdateAttr(key string, rawVal interface{}) {
	prj_val := reflect.ValueOf(p)
	pair := prj_val.Elem().FieldByName(key)
	switch key {
	case "Name":
		fallthrough
	case "Path":
		fallthrough
	case "Owner":
		fallthrough
	case "UniCode":
		val, _ := rawVal.(string)
		pair.SetString(val)
	case "Duration":
		val, _ := rawVal.(int64)
		pair.SetInt(val)
	case "Status":
		val, _ := rawVal.(PRJ_STATUS)
		pair.SetInt(int64(val))
	case "BuildTime":
		// val, _ := rawVal.(time.Time)
		// pair.Set(val)
		// TODO don't know how to code
	}
}

type PRJ_STATUS int

const (
	PRJ_UNLOADED PRJ_STATUS = iota
	PRJ_BURNING
	PRJ_BURNED
	PRJ_COMPILE_FAILED
	PRJ_BURN_FAILED
	PRJ_EXPIRED
	PRJ_DELETED
)
